package cn.ruanyun.backInterface.modules.business.balance.serviceimpl;

import cn.ruanyun.backInterface.common.enums.AddOrSubtractTypeEnum;
import cn.ruanyun.backInterface.common.enums.BalanceTypeEnum;
import cn.ruanyun.backInterface.common.enums.BooleanTypeEnum;
import cn.ruanyun.backInterface.common.enums.ProfitDetailEnum;
import cn.ruanyun.backInterface.common.utils.EmptyUtil;
import cn.ruanyun.backInterface.common.vo.PageVo;
import cn.ruanyun.backInterface.modules.base.pojo.User;
import cn.ruanyun.backInterface.modules.base.service.mybatis.IUserService;
import cn.ruanyun.backInterface.modules.business.balance.vo.AppBalanceVO;
import cn.ruanyun.backInterface.modules.business.balance.mapper.BalanceMapper;
import cn.ruanyun.backInterface.modules.business.balance.pojo.Balance;
import cn.ruanyun.backInterface.modules.business.balance.service.IBalanceService;
import cn.ruanyun.backInterface.modules.business.balance.vo.BalanceCountVo;
import cn.ruanyun.backInterface.modules.business.order.pojo.Order;
import cn.ruanyun.backInterface.modules.business.order.service.IOrderService;
import cn.ruanyun.backInterface.modules.business.orderAfterSale.pojo.OrderAfterSale;
import cn.ruanyun.backInterface.modules.business.orderAfterSale.service.IOrderAfterSaleService;
import cn.ruanyun.backInterface.modules.business.orderDetail.pojo.OrderDetail;
import cn.ruanyun.backInterface.modules.business.orderDetail.service.IOrderDetailService;
import cn.ruanyun.backInterface.modules.business.profitDetail.pojo.ProfitDetail;
import cn.ruanyun.backInterface.modules.business.profitDetail.service.IProfitDetailService;
import cn.ruanyun.backInterface.modules.business.storeIncome.pojo.StoreIncome;
import cn.ruanyun.backInterface.modules.business.storeIncome.service.IStoreIncomeService;
import cn.ruanyun.backInterface.modules.business.storeIncome.vo.StoreIncomeCountVo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import cn.ruanyun.backInterface.common.utils.ToolUtil;
import cn.ruanyun.backInterface.common.utils.SecurityUtil;
import cn.ruanyun.backInterface.common.utils.ThreadPoolUtil;


/**
 * 余额明细接口实现
 * @author zhu
 */
@Slf4j
@Service
@Transactional
public class IBalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> implements IBalanceService {


    @Autowired
    private SecurityUtil securityUtil;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IOrderDetailService orderDetailService;

    @Autowired
    private IStoreIncomeService storeIncomeService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IOrderAfterSaleService orderAfterSaleService;

    @Autowired
    private IProfitDetailService profitDetailService;



    @Override
    public void insertOrderUpdateBalance(Balance balance) {

        if (ToolUtil.isEmpty(balance.getCreateBy())) {

            balance.setCreateBy(securityUtil.getCurrUser().getId());
        } else {

            balance.setUpdateBy(securityUtil.getCurrUser().getId());
        }

        Mono.fromCompletionStage(CompletableFuture.runAsync(() -> this.saveOrUpdate(balance)))
                .publishOn(Schedulers.fromExecutor(ThreadPoolUtil.getPool()))
                .toFuture().join();
    }

    @Override
    public void removeBalance(String ids) {

        CompletableFuture.runAsync(() -> this.removeByIds(ToolUtil.splitterStr(ids)));
    }

    /**
     * app 获取用户明细
     * @return List<AppBalanceVO>
     */
    @Override
    public List<AppBalanceVO> getAppBalance(PageVo pageVo) {

        return Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Balance>lambdaQuery()
                .eq(Balance::getCreateBy, securityUtil.getCurrUser().getId())
                .orderByDesc(Balance::getCreateTime))))
        .map(balances -> balances.parallelStream().flatMap(balance -> {

            AppBalanceVO appBalanceVO = new AppBalanceVO();
            ToolUtil.copyProperties(balance, appBalanceVO);
            return Stream.of(appBalanceVO);

        }).collect(Collectors.toList()))
        .orElse(null);
    }

    @Override
    public BigDecimal getProfitByUserId(String userId) {

        return Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Balance>lambdaQuery()
                .eq(Balance::getAddOrSubtractTypeEnum, AddOrSubtractTypeEnum.ADD)
                .eq(Balance::getBooleanReturnMoney, BooleanTypeEnum.NO)
                .eq(Balance::getBalanceType, BalanceTypeEnum.SHARE_MONEY)
                .eq(Balance::getCreateBy, userId))))
        .map(balances -> balances.parallelStream().map(Balance::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add))
        .orElse(new BigDecimal(0));
    }

    @Override
    public BigDecimal getOrderFreezeMoney(String userId) {

        return Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Balance>lambdaQuery()
        .eq(Balance::getCreateBy, userId)
        .eq(Balance::getBooleanReturnMoney, BooleanTypeEnum.NO)
        .eq(Balance::getAddOrSubtractTypeEnum, AddOrSubtractTypeEnum.ADD)
        .orderByDesc(Balance::getCreateTime))))
        .map(balances -> balances.parallelStream().filter(balance -> orderService.judgeOrderFreeze(balance.getOrderId()))
        .map(Balance::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add))
        .orElse(new BigDecimal(0));
    }


    @Override
    public void resolveReturnBalance(String orderId, BigDecimal actualRefundMoney) {

        // 1.从商家收入表里面 计算商家应该退款的金额,记录余额明细 2.从消费者的余额里面增加退款的金额 3.移除其余人分佣的明细

        //1. 先确认用户余额逻辑
        Optional.ofNullable(orderService.getById(orderId)).ifPresent(order -> {


            //1.1 处理分佣
            Optional.ofNullable(ToolUtil.setListToNul(this.list(Wrappers.<Balance>lambdaQuery()
                       .eq(Balance::getAddOrSubtractTypeEnum, AddOrSubtractTypeEnum.ADD)
                       .eq(Balance::getBooleanReturnMoney, BooleanTypeEnum.NO)
                       .eq(Balance::getOrderId, orderId))))
                       .ifPresent(balances -> {

                        
                        //平台收入为0
                        Optional.ofNullable(profitDetailService.getOne(Wrappers.<ProfitDetail>lambdaQuery()
                        .eq(ProfitDetail::getOrderId, order.getId())
                        .eq(ProfitDetail::getProfitDetailEnum, ProfitDetailEnum.PLATFORM)))
                        .ifPresent(profitDetail -> {
                            
                            profitDetail.setProfitMoney(new BigDecimal(0));
                            profitDetailService.updateById(profitDetail);
                        });        


                           //计算所有分佣退回
                        List<Balance> balancesBack =  balances.parallelStream().filter(balance -> balance.getBalanceType().equals(BalanceTypeEnum.SHARE_MONEY))
                                .collect(Collectors.toList());

                           for (Balance balance : balancesBack) {

                               Optional.ofNullable(userService.getById(balance.getCreateBy())).ifPresent(user -> {

                                   user.setBalance(user.getBalance().subtract(balance.getPrice()));
                                   userService.updateById(user);
                               });
                           }

                           balances.forEach(balance -> {

                               balance.setBooleanReturnMoney(BooleanTypeEnum.YES);
                               //处理退款(排除店铺收入(因为不属于分佣))
                               if (balance.getBalanceType().equals(BalanceTypeEnum.SHARE_MONEY)) {

                                   Optional.ofNullable(userService.getById(balance.getCreateBy())).ifPresent(user -> {

                                       Balance balanceShareUser = new Balance();
                                       balanceShareUser.setTitle("")
                                               .setAddOrSubtractTypeEnum(AddOrSubtractTypeEnum.SUB)
                                               .setPrice(balance.getPrice())
                                               .setCreateBy(user.getId());

                                       //查询购买商品记录
                                       OrderDetail orderDetail = orderDetailService.getOne(
                                               Wrappers.<OrderDetail>lambdaQuery()
                                                       .eq(OrderDetail::getOrderId, order.getId())
                                       );
                                       if (EmptyUtil.isNotEmpty(orderDetail)){
                                           User createdUser = userService.getById(order.getCreateBy());
                                           balanceShareUser.setTitle(createdUser.getNickName()+"购买的商品（"+orderDetail.getName()+" ）佣金退回");
                                       }

                                       
                                       //处理资金明细
                                       Optional.ofNullable(profitDetailService.getOne(Wrappers.<ProfitDetail>lambdaQuery()
                                       .eq(ProfitDetail::getOrderId, balance.getOrderId())
                                       .eq(ProfitDetail::getCreateBy, balance.getCreateBy())))
                                       .ifPresent(profitDetail -> {

                                           profitDetail.setProfitMoney(new BigDecimal(0));
                                           profitDetailService.updateById(profitDetail);
                                       });

                                       this.save(balanceShareUser);

                                   });

                               }

                               this.updateById(balance);
                           });


                       });

               log.info(Thread.currentThread().getName() + "线程已完成分佣操作");




                //1.3 处理消费者
                Optional.ofNullable(userService.getById(order.getCreateBy())).ifPresent(userVo -> {

                    Balance balanceUser = new Balance();

                    //查询购买商品记录
                    OrderDetail orderDetail = orderDetailService.getOne(
                            Wrappers.<OrderDetail>lambdaQuery()
                                    .eq(OrderDetail::getOrderId, order.getId())
                    );

                    balanceUser.setTitle("购买的商品（"+orderDetail.getName()+"）退款")
                            .setAddOrSubtractTypeEnum(AddOrSubtractTypeEnum.ADD)
                            .setBooleanReturnMoney(BooleanTypeEnum.YES);

                    if (ToolUtil.isEmpty(actualRefundMoney)) {

                        //申请退款金额
                        BigDecimal returnMoney = orderAfterSaleService.getOrderAfterSaleReturnMoney(orderId);
                        userVo.setBalance(userVo.getBalance().add(returnMoney));

                        balanceUser.setPrice(returnMoney);
                        userService.updateById(userVo);
                        log.info("处理消费者退款成功！");


                        //资金流向明细
                        Optional.ofNullable(profitDetailService.getOne(Wrappers.<ProfitDetail>lambdaQuery()
                        .eq(ProfitDetail::getOrderId, order.getId())
                        .eq(ProfitDetail::getCreateBy, userVo.getId())))
                        .ifPresent(profitDetail -> {

                            profitDetail.setProfitMoney(profitDetail.getProfitMoney().add(returnMoney));
                            profitDetailService.updateById(profitDetail);

                        });

                    }else {

                        userVo.setBalance(userVo.getBalance().add(actualRefundMoney));
                        balanceUser.setPrice(actualRefundMoney);
                        userService.updateById(userVo);
                        log.info("处理消费者退款成功！");

                        //资金流向明细
                        Optional.ofNullable(profitDetailService.getOne(Wrappers.<ProfitDetail>lambdaQuery()
                                .eq(ProfitDetail::getOrderId, order.getId())
                                .eq(ProfitDetail::getCreateBy, userVo.getId())))
                                .ifPresent(profitDetail -> {

                                    profitDetail.setProfitMoney(profitDetail.getProfitMoney().add(actualRefundMoney));
                                    profitDetailService.updateById(profitDetail);

                                });
                    }

                    balanceUser.setCreateBy(order.getCreateBy());
                    User byId = userService.getById(order.getCreateBy());
                    balanceUser.setTitle(byId.getNickName() + balanceUser.getTitle());
                    this.save(balanceUser);
                    log.info("记录消费者明细成功！");

                    log.info(Thread.currentThread().getName() + "线程已完成消费者操作");
                });



               //1.2 处理商家
               Optional.ofNullable(userService.getById(order.getUserId())).ifPresent(store -> {

                   Balance balanceStore = new Balance();
                   User user = userService.getById(order.getCreateBy());
                   //查询购买商品记录
                   OrderDetail orderDetail = orderDetailService.getOne(
                           Wrappers.<OrderDetail>lambdaQuery()
                                   .eq(OrderDetail::getOrderId, order.getId())
                   );
                   if (EmptyUtil.isNotEmpty(orderDetail)){

                       balanceStore.setTitle(user.getNickName()+"购买的商品（"+orderDetail.getName()+" ）退款");
                   }
                   balanceStore.setAddOrSubtractTypeEnum(AddOrSubtractTypeEnum.SUB);

                   ProfitDetail profitDetailStore = profitDetailService.getOne(Wrappers.<ProfitDetail>lambdaQuery()
                   .eq(ProfitDetail::getOrderId, order.getId())
                   .eq(ProfitDetail::getProfitDetailEnum, ProfitDetailEnum.STORE)
                   .eq(ProfitDetail::getCreateBy, order.getUserId()));
                   
                   
                   if (ToolUtil.isEmpty(actualRefundMoney)) {

                       //门店当前收入
                       BigDecimal storeIncome = storeIncomeService.getStoreIncomeByOrderId(order
                               .getUserId(), order.getId());

                       log.info("当前门店的收入是:" + storeIncome);

                       log.info("当前门店的余额是" + store.getBalance());
                       
                       store.setBalance(store.getBalance().subtract(storeIncome));

                       log.info("当前的门店余额是" + store.getBalance());
                       balanceStore.setPrice(storeIncome);

                       if (ToolUtil.isNotEmpty(profitDetailStore)) {
                           profitDetailStore.setProfitMoney(new BigDecimal(0));
                       }

                       //更新退款详情
                       OrderAfterSale orderAfterSale = orderAfterSaleService.getOne(Wrappers.<OrderAfterSale>lambdaQuery()
                               .eq(OrderAfterSale::getOrderId, order.getId()));

                       orderAfterSale.setActualRefundMoney(storeIncome);
                       orderAfterSaleService.updateById(orderAfterSale);


                       //处理商家收入退款
                       Optional.ofNullable(storeIncomeService.getOne(Wrappers.<StoreIncome>lambdaQuery()
                       .eq(StoreIncome::getOrderId, order.getId())
                       .eq(StoreIncome::getCreateBy, order.getUserId())))
                        .ifPresent(storeIncome1 -> {

                            storeIncome1.setIncomeMoney(new BigDecimal(0));
                            storeIncomeService.updateById(storeIncome1);
                        });


                   }else {

                       store.setBalance(store.getBalance().subtract(actualRefundMoney));
                       balanceStore.setPrice(actualRefundMoney);

                       if (ToolUtil.isNotEmpty(profitDetailStore)) {

                           profitDetailStore.setProfitMoney(profitDetailStore.getProfitMoney().subtract(actualRefundMoney));
                       }

                       //处理门店收入
                       Optional.ofNullable(storeIncomeService.getOne(Wrappers.<StoreIncome>lambdaQuery()
                               .eq(StoreIncome::getOrderId, order.getId())
                               .eq(StoreIncome::getCreateBy, order.getUserId())))
                               .ifPresent(storeIncome2 -> {

                                   storeIncome2.setIncomeMoney(storeIncome2.getIncomeMoney().subtract(actualRefundMoney));
                                   storeIncomeService.updateById(storeIncome2);
                               });

                   }

                   log.info("处理商家退款成功！");
                   userService.updateById(store);

                   log.info("记录商家退款明细成功！");
                   balanceStore.setCreateBy(order.getUserId());
                   this.save(balanceStore);

                   if (ToolUtil.isNotEmpty(profitDetailStore)) {

                       profitDetailService.updateById(profitDetailStore);
                   }

               });

               log.info(Thread.currentThread().getName() + "线程已完成商家操作");

           });
    }

    @Override
    public BalanceCountVo getBalanceCount(String storeId) {


        List<String> orderIds;

        if (ToolUtil.isNotEmpty(storeId)) {

            orderIds = orderService.list(Wrappers.<Order>lambdaQuery().eq(Order::getUserId, storeId)).parallelStream()
                    .map(Order::getId).collect(Collectors.toList());

            //如果商家没有订单，不能让他看平台的订单，所以orderIds不能为空，我默认价格id,
            if (orderIds.size() == 0){

                orderIds.add("00000000");
            }

        }else {

            orderIds = orderService.list().parallelStream().map(Order::getId).collect(Collectors.toList());

        }

        List<Balance> balances = this.list(Wrappers.<Balance>lambdaQuery()
                .in(ToolUtil.isNotEmpty(orderIds),Balance::getOrderId, orderIds)
                .eq(Balance::getAddOrSubtractTypeEnum, AddOrSubtractTypeEnum.ADD)
                .eq(Balance::getBooleanReturnMoney, BooleanTypeEnum.NO)
                .eq(Balance::getBalanceType, BalanceTypeEnum.SHARE_MONEY));

        BalanceCountVo balanceCountVo = new BalanceCountVo();

        // TODO: 2020/5/14 0014  日收入
        List<Balance> day = balances.parallelStream()
                .filter(balance ->
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(balance.getCreateTime()).contains(getToday())
                && orderService.judgeOrderFreeze(balance.getOrderId()) )
                .collect(Collectors.toList());
        balanceCountVo.setDayIncome(day.parallelStream().map(Balance::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add));

        // TODO: 2020/5/14 0014  月收入
        List<Balance> month = balances.parallelStream().filter(balance ->
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(balance.getCreateTime()).contains(getMonth())
                && orderService.judgeOrderFreeze(balance.getOrderId())).collect(Collectors.toList());
        balanceCountVo.setMonthIncome(month.parallelStream().map(Balance::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        // TODO: 2020/5/14 0014  年收入
        List<Balance> year = balances.parallelStream().filter(balance ->
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(balance.getCreateTime()).contains(getYear())
               &&  orderService.judgeOrderFreeze(balance.getOrderId())).collect(Collectors.toList());
        balanceCountVo.setYearIncome(year.parallelStream().map(Balance::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        //总收入
        balanceCountVo.setTotalIncome(balances.parallelStream().filter(balance ->  orderService.judgeOrderFreeze(balance.getOrderId()))
                .map(Balance::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add));

        return balanceCountVo;
    }

    /**
     * 当天
     * @return
     */
    public String getToday(){
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    }

    /**
     * 当月
     * @return
     */
    public String getMonth(){
        return new SimpleDateFormat("yyyy-MM").format(new Date());
    }

    /**
     * 当年
     * @return
     */
    public String getYear(){
        return new SimpleDateFormat("yyyy").format(new Date());
    }
}